#include "XCxcD3D11Drawer.h"
#include <cmath>


XCxcD3D11Drawer::XCxcD3D11Drawer()
{
	world = new XMMATRIX;
	view = new XMMATRIX;
	projection = new XMMATRIX;
	cb = new ConstantBuffer;
}

XCxcD3D11Drawer::~XCxcD3D11Drawer()
{

	vertexLayout->Release();

	vertexShader->Release();
	pixelShader->Release();
	vertexShaderBuffer->Release();
	pixelShaderBuffer->Release();

	constantBuffer->Release();

	device->Release();
	context->Release();
	swapChain->Release();
	renderTargetView->Release();
//	delete ball;
}

void XCxcD3D11Drawer::initializeScene()
{
	D3D11_INPUT_ELEMENT_DESC layout[] = 
	{
		{ "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
		{ "COLOR", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 },
	};
	D3DCompileFromFile(L"Effects.fx", NULL, NULL, "VS", "vs_5_0", 0, 0, &vertexShaderBuffer, NULL);
	D3DCompileFromFile(L"Effects.fx", NULL, NULL, "PS", "ps_5_0", 0, 0, &pixelShaderBuffer, NULL);
	device->CreateVertexShader(vertexShaderBuffer->GetBufferPointer(), vertexShaderBuffer->GetBufferSize(), NULL, &vertexShader);
	device->CreatePixelShader(pixelShaderBuffer->GetBufferPointer(), pixelShaderBuffer->GetBufferSize(), NULL, &pixelShader);
	context->VSSetShader(vertexShader, NULL, NULL);
	context->PSSetShader(pixelShader, NULL, NULL);
	device->CreateInputLayout(layout, 2, vertexShaderBuffer->GetBufferPointer(), vertexShaderBuffer->GetBufferSize(), &vertexLayout);
	context->IASetInputLayout(vertexLayout);


	XCreateSimpleBufferNull(D3D11_BIND_CONSTANT_BUFFER, sizeof(ConstantBuffer), &constantBuffer);

	*world = XMMatrixIdentity();
	*view = XMMatrixIdentity();
	*projection = XMMatrixIdentity();
	
	XMVECTOR eye = XMVectorSet(0.0f, 0.0f, 3.0f, 0.0f);
	XMVECTOR at = XMVectorSet(0.0f, 0.0f, 0.0f, 0.0f);
	XMVECTOR up = XMVectorSet(0.0f, 1.0f, 0.0f, 0.0f);
	*view = XMMatrixLookAtLH(eye, at, up);
	
	*projection = XMMatrixPerspectiveFovLH(XM_PIDIV2, width / (float)height, 0.01f, 100.0f);

	//ball = new XD3D11Ball(this);
	//cube = new XD3D11Cube(this);
	//anchor = new XD3D11Anchor(this);
	//ball->create(15);
	//ball->setSolid(false);
	//cube->create();
	//cube->setSolid(true);
	//anchor->create();

}

void XCxcD3D11Drawer::update()
{

	//ID3D11DepthStencilView *depthStencilView;
	//ID3D11Texture2D	*depthStencilBuffer;

}

void XCxcD3D11Drawer::draw()
{
	float backColors[] = { 1.0f, 1.0f, 1.0f, 1.0f };
	context->ClearRenderTargetView(renderTargetView, backColors);

	cb->Projection = XMMatrixIdentity();
	cb->View = XMMatrixIdentity();
	cb->View = XMMatrixIdentity();
	cb->Projection = XMMatrixTranspose(*projection);
	cb->View =  XMMatrixTranspose(*view);
	cb->World =  XMMatrixTranspose(*world);
	context->UpdateSubresource(constantBuffer, 0, NULL, cb, 0, 0);
	context->VSSetConstantBuffers(0, 1, &constantBuffer);


	cb->World = XMMatrixTranspose(XMMatrixScaling(2.0f, 2.0f, 2.0f) * *world);
	context->UpdateSubresource(constantBuffer, 0, NULL, cb, 0, 0);
	context->VSSetConstantBuffers(0, 1, &constantBuffer);

	cb->World = XMMatrixTranspose(XMMatrixScaling(0.1f, 0.1f, 0.1f) * *world);
	context->UpdateSubresource(constantBuffer, 0, NULL, cb, 0, 0);
	context->VSSetConstantBuffers(0, 1, &constantBuffer);

	swapChain->Present(0, 0);
}

void XCxcD3D11Drawer::rotateY(float ang)
{
	XMVECTOR rotaxis = XMVectorSet(0.0f, 1.0f, 0.0f, 0.0f);
	*world *= XMMatrixRotationAxis(rotaxis, ang);

}

void XCxcD3D11Drawer::rotateX(float ang)
{
	XMVECTOR rotaxis = XMVectorSet(1.0f, 0.0f, 0.0f, 0.0f);
	*world *= XMMatrixRotationAxis(rotaxis, ang);
}

void XCxcD3D11Drawer::rotateZ(float ang)
{
	XMVECTOR rotaxis = XMVectorSet(0.0f, 0.0f, 1.0f, 0.0f);
	*world *= XMMatrixRotationAxis(rotaxis, ang);
}

void XCxcD3D11Drawer::setHWND(HWND hWnd)
{
	this->hWnd = hWnd;
}

void XCxcD3D11Drawer::setWidth(int width)
{
	this->width = width;
}

void XCxcD3D11Drawer::setHeight(int height)
{
	this->height = height;
}

bool XCxcD3D11Drawer::initializeD3D11App()
{
	DXGI_MODE_DESC bufferDesc;
	ZeroMemory(&bufferDesc, sizeof(DXGI_MODE_DESC));
	bufferDesc.Height = height;
	bufferDesc.Width = width;
	bufferDesc.RefreshRate.Denominator = 1;
	bufferDesc.RefreshRate.Numerator = 60;
	bufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
	bufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
	bufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;

	DXGI_SWAP_CHAIN_DESC swapChainDesc;
	ZeroMemory(&swapChainDesc, sizeof(DXGI_SWAP_CHAIN_DESC));
	swapChainDesc.BufferCount = 1;
	swapChainDesc.BufferDesc = bufferDesc;
	swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
	swapChainDesc.OutputWindow = hWnd;
	swapChainDesc.SampleDesc.Count = 4;
	swapChainDesc.SampleDesc.Quality = 0;
	swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
	swapChainDesc.Windowed = TRUE;

	D3D11CreateDeviceAndSwapChain(
		NULL,
		D3D_DRIVER_TYPE_HARDWARE,
		NULL,
		NULL,
		NULL,
		NULL,
		D3D11_SDK_VERSION,
		&swapChainDesc,
		&swapChain,
		&device,
		NULL,
		&context
		);

	ID3D11Texture2D *backBuffer;
	swapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), (LPVOID *)&backBuffer);
	device->CreateRenderTargetView(backBuffer, NULL, &renderTargetView);
	// backBuffer->Release();
	// context->OMSetRenderTargets(1, &renderTargetView, NULL);

	D3D11_VIEWPORT viewport;
	ZeroMemory(&viewport, sizeof(D3D11_VIEWPORT));
	viewport.TopLeftX = 0;
	viewport.TopLeftY = 0;
	viewport.Width = width;
	viewport.Height = height;
	viewport.MinDepth = 0.0f;
	viewport.MaxDepth = 1.0f;
	context->RSSetViewports(1, &viewport);

	context->OMSetRenderTargets(1, &renderTargetView, NULL);

	return true;
}


void XCxcD3D11Drawer::XCreateSimpleBuffer(UINT bindFlags, const void * pSysMem, UINT byteWidth, ID3D11Buffer ** buffer)
{
	D3D11_BUFFER_DESC bd;
	ZeroMemory(&bd, sizeof(bd));
	bd.ByteWidth = byteWidth;
	bd.BindFlags = bindFlags;
	bd.Usage = D3D11_USAGE_DEFAULT;
	bd.CPUAccessFlags = 0;

	D3D11_SUBRESOURCE_DATA data;
	ZeroMemory(&data, sizeof(data));
	data.pSysMem = pSysMem;
	device->CreateBuffer(&bd, &data, buffer);
}

void XCxcD3D11Drawer::XCreateSimpleBufferNull(UINT bindFlags, UINT byteWidth, ID3D11Buffer ** buffer)
{
	D3D11_BUFFER_DESC bd;
	ZeroMemory(&bd, sizeof(bd));
	bd.ByteWidth = byteWidth;
	bd.BindFlags = bindFlags;
	bd.Usage = D3D11_USAGE_DEFAULT;
	bd.CPUAccessFlags = 0;

	device->CreateBuffer(&bd, NULL, buffer);
}

ID3D11Device * XCxcD3D11Drawer::getDevice() const
{
	return device;
}

ID3D11DeviceContext * XCxcD3D11Drawer::getContext() const
{
	return context;
}